package com.material.vtool.controller;

import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils;
import com.google.common.collect.Maps;
import com.material.vtool.entity.BBaseInfoEntity;
import com.material.vtool.entity.BUserInfoEntity;
import com.material.vtool.entity.reqEntity.WxUserLoginReqBean;
import com.material.vtool.entity.respEntity.RespData;
import com.material.vtool.entity.respEntity.ReturnCode;
import com.material.vtool.service.BaseInfoService;
import com.material.vtool.service.UserInfoService;
import com.material.vtool.service.UserMaterialTypeService;
import com.material.vtool.task.UserAsyncTask;
import com.material.vtool.utils.DateUtil;
import com.material.vtool.utils.ToolUtil;
import com.material.vtool.wechat.service.WeixinServiceDL;
import com.material.vtool.wechat.service.WeixinServiceMap;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * 微信相关
 */
@Slf4j
@RestController
@RequestMapping("/wechat")
public class WechatController {
    @Autowired
    private ObjectFactory<WeixinServiceDL> objectFactory;

    @Autowired
    private BaseInfoService baseInfoService;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private UserAsyncTask userAsyncTask;

    @Autowired
    private UserMaterialTypeService userMaterialTypeService;

    /**
     * 用户登录
     * @param miniCode 小程序标识
     * @param encryptedData 包括敏感数据在内的完整用户信息的加密数据(https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserProfile.html)
     * @param ivStr 加密算法的初始向量
     * @param wxUserLoginReqBean 封装微信登录临时 code 的实体类
     * @return
     */
    @PostMapping(value = "/wxUserLogin", produces = "application/json;charset=UTF-8")
    public RespData wxUserLogin(@RequestHeader("miniCode") String miniCode,
                                @RequestHeader("encryptedData") String encryptedData,
                                @RequestHeader("iv") String ivStr,
                                @RequestBody WxUserLoginReqBean wxUserLoginReqBean) throws Exception {
        if (wxUserLoginReqBean == null || StringUtils.isBlank(wxUserLoginReqBean.getCode())) {
            RespData respData = new RespData();
            respData.setCode(ReturnCode.CLIENT_ERROR);
            respData.setMsg("参数错误");
            return respData;
        }

        log.info(String.format("[ miniCode ] = %s, [ encryptedData ] = %s, [ iv ] = %s, [ code ] = %s", miniCode, encryptedData, ivStr, wxUserLoginReqBean.getCode()));

        // Map 中查找对应的小程序服务类
        WeixinServiceDL weixinService = WeixinServiceMap.getWeixinService(miniCode);
        if (weixinService == null) {
            weixinService = objectFactory.getObject();
            weixinService.reSetConfigStorage(miniCode);
            WeixinServiceMap.putWeixinService(miniCode, weixinService);
        }

        // 根据 code 获取小程序信息
        WxMaJscode2SessionResult wxMaJscode2SessionResult = null;
        try {
            log.info(String.format("[WeixinService] = %s [WxUserLoginReqBean] = %s", weixinService, wxUserLoginReqBean));
            wxMaJscode2SessionResult = weixinService.jsCode2SessionInfo(wxUserLoginReqBean.getCode());
        } catch (WxErrorException e) {
            RespData respData = new RespData();
            respData.setCode(ReturnCode.SERVER_ERROR);

            Map<String, Object> resultMap = Maps.newHashMapWithExpectedSize(2);
            resultMap.put("code", wxUserLoginReqBean.getCode());

            respData.setData(resultMap);
            respData.setMsg("授权码已过期");
            return respData;
        }

        // 根据小程序 openid 查询用户是否存在
        String openId = wxMaJscode2SessionResult.getOpenid();
        String sessionKey = wxMaJscode2SessionResult.getSessionKey();
        log.info(String.format("[wxOpenId] = %s [wxSessionKey] = %s", openId, sessionKey));

        int finalUserId = Optional.ofNullable(userInfoService.getUserIdByOpenId(openId)).orElse(0);
        log.info("[finalUserId：]" + finalUserId);

        // 获取小程序信息
        BBaseInfoEntity bBaseInfoEntity = baseInfoService.getMiniInfoByCode(miniCode);
        // 获取微信用户信息
        /*String decrypt = WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr);// 测试用
        log.info("[decrypt] = " + decrypt);*/
        WxMaUserInfo userInfo = weixinService.getUserService().getUserInfo(sessionKey, encryptedData, ivStr);

        // 如果用户存在，则更新用户最后一次登录时间; 如果用户不存在，则把用户数据写入数据库
        if (finalUserId > 0) {
            userAsyncTask.updateUserInfo(Integer.valueOf(finalUserId), userInfo.getNickName());
        } else {
            BUserInfoEntity bUserInfoEntity = new BUserInfoEntity();
            try {
                bUserInfoEntity.setOpenId(openId);
                bUserInfoEntity.setNickName(userInfo.getNickName());// 小程序昵称：第一次创建该字段用 微信昵称
                bUserInfoEntity.setUserName(userInfo.getNickName());// 微信昵称
                bUserInfoEntity.setAvatarUrl(userInfo.getAvatarUrl());// 微信头像
                bUserInfoEntity.setWxUnionId(wxMaJscode2SessionResult.getUnionid());
                bUserInfoEntity.setMiniId(bBaseInfoEntity.getId());
                bUserInfoEntity.setMiniCode(miniCode);
                bUserInfoEntity.setCreateTime(DateUtil.getCurDate());
                bUserInfoEntity.setLastActiveTime(DateUtil.getCurDate());
                userInfoService.addWxUserInfo(bUserInfoEntity);
                finalUserId = bUserInfoEntity.getUserId();
            } catch (Exception e) {

            }

            // 用户订阅频道
            userMaterialTypeService.initializeUserMaterialType(Integer.valueOf(finalUserId), miniCode);
        }

        // 返回用户信息
        HashMap<Object, Object> resultMap = Maps.newHashMapWithExpectedSize(3);
        resultMap.put("userId", String.valueOf(finalUserId));
        resultMap.put("userSessionId", ToolUtil.md5Encode(finalUserId + openId));

        RespData respData = new RespData();
        respData.setCode(ReturnCode.NORMAL_SUCC);
        respData.setMsg("成功");
        respData.setData(resultMap);
        return respData;
    }

    @GetMapping(value = "/getSessionKey", produces = "application/json;charset=UTF-8")
    public RespData getSessionKey(String userId, String openId) throws Exception {
        HashMap<Object, Object> resultMap = Maps.newHashMapWithExpectedSize(3);
        resultMap.put("userId", userId);
        resultMap.put("userSessionId", ToolUtil.md5Encode(userId + openId));// 1041f205711ed488137cc18638d55371

        RespData respData = new RespData();
        respData.setCode(ReturnCode.NORMAL_SUCC);
        respData.setMsg("成功");
        respData.setData(resultMap);
        return respData;
    }
}
